package yartiss.service.model;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import yartiss.engine.simulation.Event;
import yartiss.engine.simulation.SimulationParameters;
import yartiss.engine.simulation.events.EventGenerator;
import yartiss.engine.simulation.io.DefaultParamsParser;
import yartiss.engine.simulation.system.ITask;

public class EventsTraceModel extends AbstractEventsModel {

	private final ArrayList<Event> eventQue = new ArrayList<Event>();
	private final HashMap<ITask, List<Event>> eventsQueByTask = new HashMap<ITask, List<Event>>();
	private final SimulationParameters parameters; 
	private final Map<Integer, ITask> tasksById = new HashMap<Integer, ITask>();
	
	public EventsTraceModel(String file) throws FileNotFoundException{
		Scanner scanner = new Scanner(new File(file));
		parameters = DefaultParamsParser.parse(scanner);
		int id = 1;
		for (ITask task : parameters.getTaskSet()) {
			tasksById.put(Integer.valueOf(id), task);
			id++;
		}
		parseEventQue(scanner);
		scanner.close();
	}
	
	private void parseEventQue(Scanner scanner) {
		EventGenerator evGen = new EventGenerator();
		while(scanner.hasNextLine()){
			String line = scanner.nextLine();
			if(!line.isEmpty()){
				String [] tokens = line.split("\t");
				long date = Long.parseLong(tokens[0]);
				long energyLevel = Long.parseLong(tokens[1]);
				int taskId = Integer.parseInt(tokens[2].substring(1));
				String eventType = tokens[3];
				Map<String , Long> metric = new HashMap<String, Long>();
				metric.put(Event.EnergyLevel, energyLevel);
				Event e = evGen.getNewInstance(eventType, tasksById.get(Integer.valueOf(taskId)),0, date, metric);
				eventQue.add(e);
				List<Event> eq = null;
				if(!eventsQueByTask.containsKey(e.getTask())){
					eq = new ArrayList<Event>();
					eventsQueByTask.put(e.getTask(), eq);
				}
				else eq = eventsQueByTask.get(e.getTask());
				eq.add(e);
			}
		}
	}

	@Override
	public Iterable<ITask> getAllTasks() {
		return parameters.getTaskSet();
	}

	/**
	 * 
	 */
	@Override
	public List<Event> getEvents(long startTime, long duration) {
		int from=-1, to=0;
		long  endTime = startTime+duration;
		for (Event e : eventQue) {
			if(from<0  && e.getDate()==startTime)from=eventQue.indexOf(e);
			if(from>=0 && e.getDate()==endTime)to=eventQue.indexOf(e);
			if(from>=0 && e.getDate()>endTime)break;
		}
		return eventQue.subList(from, to);
	}

	/**
	 * 
	 */
	@Override
	public List<Event> getTaskEvents(ITask task, long startTime, long duration) {
		List<Event> taskEvents = eventsQueByTask.get(task);
		int from=-1, to=0;
		long  endTime = startTime+duration;
		for (Event e : taskEvents) {
			if(from<0  && e.getDate()==startTime)from=taskEvents.indexOf(e);
			if(from>=0 && e.getDate()==endTime)to=taskEvents.indexOf(e);
			if(from>=0 && e.getDate()>endTime)break;
		}
		return taskEvents.subList(from,  to);
	}

	@Override
	public List<Event> getAllEvents() {
		return eventQue;
	}

	@Override
	public List<Event> getAllTaskEvents(ITask task) {
		return new LinkedList<Event>(eventsQueByTask.get(task));
	}
	
	public SimulationParameters getSimulParameters(){
		return parameters;
	}
	
	@Override
	public long getFinishTime() {
		if(eventQue.size()>0)
			return eventQue.get(eventQue.size()-1).getDate();
		return 0;
	}

	@Override
	public List<Event> getProcEvents(int procId, long startTime, long duration) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<Event> getAllProcEvents(int procId) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Iterable<Integer> getAllProcsIds() {
		// TODO Auto-generated method stub
		return null;
	}

	

}
